/*******************************************************************************
 * Copyright 2020 huanggefan.cn
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/

package main

import (
	"flag"
	"log"
	"net"
	"net/http"
	"runtime"
	"time"

	"github.com/jinzhu/gorm"

	"gitee.com/WisdomClassroom/core"
	"gitee.com/WisdomClassroom/core/models"
	"gitee.com/WisdomClassroom/resource/global"
	"gitee.com/WisdomClassroom/resource/handler"

	_ "github.com/jinzhu/gorm/dialects/postgres"
	_ "github.com/jinzhu/gorm/dialects/sqlite"
)

var (
	BuildTag  string = ""
	BuildGo   string = ""
	BuildTime string = ""
)

func main() {
	core.PublicFlag(BuildTag, BuildGo, BuildTime)
	core.PublicServerFlag()
	flag.StringVar(&global.Dir, "save-dir", "./data", "save file")
	flag.Parse()

	if core.FlagHelp {
		flag.Usage()
		return
	}
	if core.FlagVersion {
		core.PublicVersion()
		return
	}
	if !core.FlagUseSqlite && !core.FlagUsePG {
		flag.Usage()
		return
	}

	if core.FlagLogWithUDP {
		addr, err := net.ResolveUDPAddr("udp", core.FlagLogAddr)
		if err != nil {
			log.Fatalln(err)
		}
		global.Logger, err = core.NewUDPLogger(core.FlagLogLevel, addr, 10240)
		if err != nil {
			log.Fatalln(err)
		}
	} else {
		global.Logger = core.NewLogger(core.FlagLogLevel)
	}

	if core.FlagPPROFEnable {
		go core.StartPPOFDebug(http.Server{Addr: core.FlagPPROFListen}, true)
		time.Sleep(1 * time.Second)
	}

	global.Logger.Info("http listen at: http://" + core.FlagHttpListen)
	if core.FlagLogWithUDP {
		global.Logger.Info("log to: udp://" + core.FlagLogAddr)
	}

	var err error
	if core.FlagUseSqlite {
		global.DB, err = gorm.Open("sqlite3", core.FlagSqliteDB)
		if err != nil {
			errInfo := "failed to open database: " + err.Error()
			global.Logger.Error(errInfo)
			return
		}
	} else if core.FlagUsePG {
		global.DB, err = gorm.Open("postgres", models.GetPgSQLConf())
		if err != nil {
			errInfo := "failed to connect database: " + err.Error()
			global.Logger.Error(errInfo)
			return
		}
	} else {
		flag.Usage()
		return
	}

	global.TokenCert = core.NewTokenCert(core.FlagTokenCert)

	if core.FlagLogLevel == core.LogDebug {
		global.DB.LogMode(true)
		global.DB.SetLogger(global.Logger)
	}

	mux := new(http.ServeMux)
	server := http.Server{
		Addr:              core.FlagHttpListen,
		Handler:           mux,
		TLSConfig:         nil,
		ReadTimeout:       0,
		ReadHeaderTimeout: 0,
		WriteTimeout:      0,
		IdleTimeout:       0,
		MaxHeaderBytes:    0,
		TLSNextProto:      nil,
		ConnState:         nil,
		ErrorLog:          nil,
		BaseContext:       nil,
		ConnContext:       nil,
	}

	const apiV1Prefix = "/api/v1/resource"
	const (
		putJPG         = apiV1Prefix + "/putJPG"
		putPNG         = apiV1Prefix + "/putPNG"
		putPPT         = apiV1Prefix + "/putPPT"
		putXLS         = apiV1Prefix + "/putXLS"
		putDOC         = apiV1Prefix + "/putDOC"
		putPPTX        = apiV1Prefix + "/putPPTX"
		putXLSX        = apiV1Prefix + "/putXLSX"
		putDOCX        = apiV1Prefix + "/putDOCX"
		putPDF         = apiV1Prefix + "/putPDF"
		putMP3         = apiV1Prefix + "/putMP3"
		putMP4         = apiV1Prefix + "/putMP4"
		putZIP         = apiV1Prefix + "/putZIP"
		getResource    = apiV1Prefix + "/getResource"
		deleteResource = apiV1Prefix + "/deleteResource"
		listResource   = apiV1Prefix + "/listResource"
	)

	mux.HandleFunc(putJPG, handler.GenPUTHandleFunc(core.FileTypeCodeJPG))
	mux.HandleFunc(putPNG, handler.GenPUTHandleFunc(core.FileTypeCodePNG))
	mux.HandleFunc(putPPT, handler.GenPUTHandleFunc(core.FileTypeCodePPT))
	mux.HandleFunc(putXLS, handler.GenPUTHandleFunc(core.FileTypeCodeXLS))
	mux.HandleFunc(putDOC, handler.GenPUTHandleFunc(core.FileTypeCodeDOC))
	mux.HandleFunc(putPPTX, handler.GenPUTHandleFunc(core.FileTypeCodePPTX))
	mux.HandleFunc(putXLSX, handler.GenPUTHandleFunc(core.FileTypeCodeXLSX))
	mux.HandleFunc(putDOCX, handler.GenPUTHandleFunc(core.FileTypeCodeDOCX))
	mux.HandleFunc(putPDF, handler.GenPUTHandleFunc(core.FileTypeCodePDF))
	mux.HandleFunc(putMP3, handler.GenPUTHandleFunc(core.FileTypeCodeMP3))
	mux.HandleFunc(putMP4, handler.GenPUTHandleFunc(core.FileTypeCodeMP4))
	mux.HandleFunc(putZIP, handler.GenPUTHandleFunc(core.FileTypeCodeZIP))
	mux.HandleFunc(getResource, handler.HandleFuncGetResource)
	mux.HandleFunc(deleteResource, handler.HandleFuncDeleteResource)
	mux.HandleFunc(listResource, handler.HandleFuncListResource)
	mux.HandleFunc("/", handler.HandleFuncNotFound)

	if err := server.ListenAndServe(); err != nil {
		log.Fatalln(err)
	}
}

func init() {
	runtime.GOMAXPROCS(1)
}
